/**
 * 对象操作工具类
 */
export class ObjUtil {
  /**
   * 对日期进行格式化， 和C#大致一致 默认yyyy-MM-dd HH:mm:ss
   * 可不带参数 一个日期参数 或一个格式化参数
   * @param date 要格式化的日期
   * @param format 进行格式化的模式字符串
   *     支持的模式字母有：
   *     y:年,
   *     M:年中的月份(1-12),
   *     d:月份中的天(1-31),
   *     H:小时(0-23),
   *     h:小时(0-11),
   *     m:分(0-59),
   *     s:秒(0-59),
   *     f:毫秒(0-999),
   *     q:季度(1-4)
   * @return String
   * @author adswads@gmail.com
   */
  public dateFormat(date?: any, format?: string): string {
    //无参数
    if (date == undefined && format == undefined) {
      date = new Date();
      format = "yyyy-MM-dd HH:mm:ss";
    }
    //无日期
    else if (typeof date == "string") {
      format = date;
      date = new Date();
    }
    //无格式化参数
    else if (format === undefined) {
      format = "yyyy-MM-dd HH:mm:ss";
    } else {
    }
    //没有分隔符的特殊处理
    var map = {
      y: date.getFullYear() + "", //年份
      M: date.getMonth() + 1 + "", //月份
      d: date.getDate() + "", //日
      H: date.getHours(), //小时 24
      m: date.getMinutes() + "", //分
      s: date.getSeconds() + "", //秒
      q: Math.floor((date.getMonth() + 3) / 3) + "", //季度
      f: date.getMilliseconds() + "", //毫秒
    };
    //小时 12
    if (map["H"] > 12) {
      map["h"] = map["H"] - 12 + "";
    } else {
      map["h"] = map["H"] + "";
    }
    map["H"] += "";
    var reg = "yMdHhmsqf";
    var all = "",
      str = "";
    for (var i = 0, n = 0; i < reg.length; i++) {
      n = format.indexOf(reg[i]);
      if (n < 0) {
        continue;
      }
      all = "";
      for (; n < format.length; n++) {
        if (format[n] != reg[i]) {
          break;
        }
        all += reg[i];
      }
      if (all.length > 0) {
        if (all.length == map[reg[i]].length) {
          str = map[reg[i]];
        } else if (all.length > map[reg[i]].length) {
          if (reg[i] == "f") {
            str =
              map[reg[i]] +
              this.charString("0", all.length - map[reg[i]].length);
          } else {
            str =
              this.charString("0", all.length - map[reg[i]].length) +
              map[reg[i]];
          }
        } else {
          switch (reg[i]) {
            case "y":
              str = map[reg[i]].substr(map[reg[i]].length - all.length);
              break;
            case "f":
              str = map[reg[i]].substr(0, all.length);
              break;
            default:
              str = map[reg[i]];
              break;
          }
        }
        format = format.replace(all, str);
      }
    }
    return format;
  }

  /**
   * 返回字符串 为n个char构成
   * @param char 重复的字符
   * @param count 次数
   * @return String
   * @author adswads@gmail.com
   */
  public charString(char: string, count: number): string {
    var str: string = "";
    while (count--) {
      str += char;
    }
    return str;
  }

  /**
   * 在一个数组里删除特定某个元素的方法。================
   * @param array 要被删除数据的数组。
   * @param item 数组里要被剔除的元素。
   */
  removeItemInArray(array: any[], item) {
    let index = array.indexOf(item);
    if (index > -1) {
      array.splice(index, 1);
    }
  }

  /**
   * 更替数组
   * @param target 需要更换目标数组
   * @param newArr 用来插入目标数组的数组
   */
  replaceArr(target: any[], newArr: any[]) {
    target.splice(0);
    target.push(...newArr);
  }

  /**
   * 通过指定的属性名在数组查找对应的元素
   * @param arr 需要查找数组
   * @param value 需要找到的属性对应的值
   * @param attr 查找的属性名
   */
  findArrByValue(arr: any[], value: any, attr: string) {
    return arr[arr.findIndex((item) => item[attr] == value)];
  }

  /**
   * 数组转化索引数组(对象)
   * @param arr 需要转化的数组
   * @param attr 需要拿来做索引的属性名
   */
  arrTransObj<T>(arr: T[], attr: string): { [propName: string]: T } {
    let obj: { [propName: string]: T } = {};
    arr.forEach((data) => {
      obj[data[attr]] = data;
    });
    return obj;
  }

  /**
   * 索引数组(对象)转换数组
   * @param obj 需要转换的索引数组(对象)
   * @returns 返回数组
   */
  objTransArr<T>(obj: { [propName: string]: T }) {
    let arr: T[] = [];
    for (let key in obj) {
      arr.push(obj[key]);
    }
    return arr;
  }

  /**
   * 数组强类型
   * @param obj
   * @param key
   */
  strongArr<T>(obj: { [propName: string]: T } | T[], key: string | number): T {
    return obj[key];
  }

  /** 克隆(不能是javascript对象) */
  clone<T>(obj: T): T {
    let o;
    switch (typeof obj) {
      case "undefined":
        break;
      case "string":
        o = obj + "";
        break;
      case "number":
        o = <any>obj - 0;
        break;
      case "boolean":
        o = obj;
        break;
      case "object":
        if (obj === null) {
          o = null;
        } else {
          if (obj instanceof Array) {
            o = [];
            for (let i = 0; i < obj.length; i++) {
              o.push(this.clone(obj[i]));
            }
          } else {
            o = {};
            for (let k in obj) {
              o[k] = this.clone(obj[k]);
            }
          }
        }
        break;
      default:
        o = obj;
        break;
    }
    return o;
  }

  assign<T>(target: T, source: T): T {
    return Object.assign(target, source);
  }

  /**
   * 生成GUID
   * @return {string}
   */
  guid(): string {
    function S4(): string {
      return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
    }
    let guid: string = "";
    for (let i = 0; i < 8; i++) {
      guid += S4();
    }
    return guid.toUpperCase();
  }

  /** 查找索引数组 */
  find<T>(
    objs: { [propName: string]: T } | T[],
    cb: (obj: T, key?: string) => boolean
  ): T {
    for (let key in objs) {
      if (cb(objs[key], key)) return objs[key];
    }
    return undefined;
  }

  /**
   * 查找索引数组的key
   * @param objs
   * @param cb
   */
  findKey<T>(
    objs: { [propName: string]: T } | T[],
    cb: (obj: T, key?: string) => boolean
  ): string {
    for (let key in objs) {
      if (cb(objs[key], key)) return key;
    }
    return undefined;
  }

  /** 索引数据map功能 */
  map<T, K>(
    objs: { [propName: string]: T } | T[],
    cb: (obj: T, key?: string) => K
  ): K[] {
    let list: K[] = [];
    for (let key in objs) {
      list.push(cb(objs[key], key));
    }
    return list;
  }

  /** 索引数组循环遍历 */
  forEach<T>(
    objs: { [propName: string]: T } | T[],
    cb: (obj: T, key?: string) => void
  ) {
    for (let key in objs) {
      cb(objs[key], key);
    }
  }

  /** 测试一个数组内的所有元素是否都能通过某个指定函数的测试 */
  every<T>(
    objs: { [propName: string]: T } | T[],
    cb: (obj: T, key?: string) => boolean
  ): boolean {
    for (let key in objs) {
      if (!cb(objs[key], key)) return false;
    }
    return true;
  }

  /** 判断一个数组是否包含一个指定的值 */
  includes<T>(
    objs: { [propName: string]: T } | T[],
    cb: (obj: T, key?: string) => boolean
  ): boolean {
    for (let key in objs) {
      if (cb(objs[key], key)) return true;
    }
    return false;
  }
}

export const objUtil = new ObjUtil();
